<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传服务</title>
    <link rel="stylesheet" href="lib/layui/css/layui.css">
    <script src="lib/layui/layui.js"></script>
    <link rel="icon" href="logo/logo.png">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body>

<div class="layui-upload">
    <fieldset class="layui-elem-field" style="margin-bottom: 8px">
        <legend>查看</legend>
        <div class="layui-field-box">
            <form id="query-form" class="layui-form" style="margin-bottom: 8px; width: 100%">
                <div class="layui-col-md4 layui-input-inline" style="margin-right: 8px;width: 20%">
                    <input type="text" id="originName" name="originName" value="" placeholder="文件名称"
                           class="layui-input">
                </div>
                <button class="layui-btn" lay-submit lay-filter="button-search">
                    <i class="layui-icon layui-icon-search"></i>搜索
                </button>
                <button id="reset" type="reset" class="layui-btn layui-btn-primary">
                    <i class="layui-icon layui-icon-refresh"></i>重置
                </button>
                <button id="fire" class="layui-btn layui-btn-danger">
                    <i class="layui-icon layui-icon-fire"></i>删除
                </button>
                <button id="qrCode" class="layui-btn layui-bg-purple">
                    <i class="layui-icon layui-icon-cellphone-fine"></i>扫码
                </button>
            </form>
            <table class="layui-hide" id="table-file-list" lay-filter="table-file-list"></table>
        </div>
    </fieldset>
    <fieldset class="layui-elem-field">
        <legend style="padding-bottom: 10px">上传</legend>
        <button type="button" class="layui-btn layui-btn-normal" id="button-upload-select"><i
                class="layui-icon layui-icon-templeate-1"></i>选择
        </button>
        <button type="button" class="layui-btn" id="button-upload-action">
            <i class="layui-icon layui-icon-upload-drag"></i>上传
        </button>
        <div class="layui-upload-list">
            <table class="layui-table">
                <thead>
                <th>文件名</th>
                <th>大小</th>
                <th>上传进度</th>
                <th>操作</th>
                </thead>
                <tbody id="table-upload-list"></tbody>
            </table>
        </div>
    </fieldset>
</div>

<style>
    /* 默认样式 */
    .layui-upload {
        /* 假设你的页面宽度为固定值或者自适应宽度 */
        width: 100%; /* 可以根据实际情况调整 */
        /* 居中显示 */
        max-width: 1200px; /* 设置最大宽度，避免过于宽松 */
        padding: 0 20px; /* 设置左右留白 */
        margin: 10px auto 0;
    }

    .layui-elem-field {
        width: 100%; /* 充满父容器宽度 */
        max-width: 1200px; /* 最大宽度，避免过宽 */
        margin: 0 auto; /* 居中显示 */
        padding: 0 20px; /* 左右留白 */
    }

    .layui-field-box {
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between; /* 左右两边对齐，中间留空 */
    }

    .layui-upload-list {
        width: 100%; /* 充满父容器宽度 */
        margin-top: 10px; /* 上方留白 */
    }

    .layui-table {
        width: 100%; /* 充满父容器宽度 */
    }

    fieldset {
        margin-right: 20px;
    }

    /* 在手机端或较窄屏幕上，调整内部元素的宽度 */
    @media (max-width: 768px) {
        .layui-upload {
            padding: 0 10px; /* 缩小留白 */
        }

        .layui-elem-field {
            padding: 0 10px; /* 在较窄的屏幕上减少留白 */
        }
    }

    /* 自定义 layer.confirm 的样式 */
    .layui-layer-dialog {
        width: 30% !important; /* 设置宽度为手机屏幕宽度的80% */
        top: 30% !important; /* 设置顶部位置为屏幕高度的30% */
        left: 35% !important; /* 设置左侧位置为屏幕宽度的10% */
    }

</style>

<script>
    layui.use(function () {
        var table = layui.table;
        var upload = layui.upload;
        var element = layui.element;
        var form = layui.form;
        var $ = layui.$;

        // 制作多文件上传表格
        var uploadListIns = upload.render({
            elem: '#button-upload-select',
            elemList: $('#table-upload-list'), // 列表元素对象
            url: '/file', // 实际使用时改成您自己的上传接口即可。
            method: 'post',
            accept: 'file',
            multiple: true,
            number: 10,
            auto: false,
            bindAction: '#button-upload-action',
            response: {
                statusCode: 200, //重新规定成功的状态码为 200，table 组件默认为 0
            },
            choose: function (obj) {
                var that = this;
                var files = this.files = obj.pushFile(); // 将每次选择的文件追加到文件队列
                // 读取本地文件
                obj.preview(function (index, file, result) {
                    var tr = $(['<tr id="upload-' + index + '">',
                        '<td>' + file.name + '</td>',
                        '<td>' + formatBytes(file.size) + '</td>',
                        '<td><div class="layui-progress" lay-filter="progress-demo-' + index + '"><div class="layui-progress-bar" lay-percent=""></div></div></td>',
                        '<td>',
                        '<button class="layui-btn layui-btn-xs demo-reload layui-hide">重传</button>',
                        '<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>',
                        '</td>',
                        '</tr>'].join(''));

                    // 单个重传
                    tr.find('.demo-reload').on('click', function () {
                        obj.upload(index, file);
                    });

                    // 删除
                    tr.find('.demo-delete').on('click', function () {
                        delete files[index]; // 删除对应的文件
                        tr.remove(); // 删除表格行
                        // 清空 input file 值，以免删除后出现同名文件不可选
                        uploadListIns.config.elem.next()[0].value = '';
                    });

                    that.elemList.append(tr);
                    element.render('progress'); // 渲染新加的进度条组件
                });
            },
            done: function (res, index, upload) { // 成功的回调
                var that = this;
                // if(res.code == 0){ // 上传成功
                var tr = that.elemList.find('tr#upload-' + index)
                var tds = tr.children();
                tds.eq(3).html(''); // 清空操作
                delete this.files[index]; // 删除文件队列已经上传成功的文件
            },
            allDone: function (obj) { // 多文件上传完毕后的状态回调
                if (obj.successful === obj.total) {
                    layer.msg("上传成功！", {icon: 1});
                }
                tableReload();
            },
            error: function (index, upload) { // 错误回调
                var that = this;
                var tr = that.elemList.find('tr#upload-' + index);
                var tds = tr.children();
                // 显示重传
                tds.eq(3).find('.demo-reload').removeClass('layui-hide');
            },
            progress: function (n, elem, e, index) { // 注意：index 参数为 layui 2.6.6 新增
                element.progress('progress-demo-' + index, n + '%'); // 执行进度条。n 即为返回的进度百分比
            }
        });

        // 创建渲染实例
        table.render({
            elem: '#table-file-list',
            url: '/file', // 此处为静态模拟数据，实际使用时需换成真实接口
            page: true,
            request: {
                pageName: 'pageNum', // 页码的参数名称，默认：page
                limitName: 'pageSize' // 每页数据条数的参数名，默认：limit
            },
            response: {
                statusCode: 200, //重新规定成功的状态码为 200，table 组件默认为 0
            },
            parseData: function (res) { // res 即为原始返回的数据
                return {
                    "code": res.code, // 解析接口状态
                    "msg": res.msg, // 解析提示文本
                    "count": res.data.total, // 解析数据长度
                    "data": res.data.list // 解析数据列表
                };
            },
            cols: [[
                {title: '选择', width: '5%', type: 'checkbox'},
                {field: 'LAY_INDEX', width: '10%', title: '序号', templet: '<div>{{d.LAY_INDEX + 1}}</div>'},
                {
                    field: 'name',
                    width: '45%',
                    title: '预览',
                    templet: '<a target="_blank" href="{{d.snowName}}">{{d.originName}}</a>'
                },
                {
                    field: 'size', width: '15%', title: '大小', templet: function (d) {
                        return formatBytes(d.size);
                    }
                },
                {
                    field: 'createTime',
                    width: '25%',
                    title: '上传时间',
                },
            ]]
        });

        // 绑定重置按钮事件
        $("#reset").click(function () {
            tableReload();
        });

        // websocket链接
        $.ajax({
            url: "file/ipv4",
            success: function (res) {
                let socket = new WebSocket(`ws://${res.msg}/websocket`);

                socket.onmessage = function (event) {
                    layer.closeAll();
                    layer.msg(event.data);
                    tableReload();
                };
            }
        });

        var htmlContent = `
            <input type="password" id="password" name="password" placeholder="密码" class="layui-input" autofocus>
        `;

        // 绑定删除按钮事件
        $("#fire").click(function () {
            let snowUrls = table.checkStatus("table-file-list").data.map(item => item.snowName);
            if (snowUrls.length === 0) {
                layer.msg("未选择任何文件", {icon: 2});
                return false;
            }
            layer.confirm(htmlContent, {icon: 4, skin: 'custom-confirm-style'}, function () {
                let password = $("#password").val();
                let delVo = {snowUrls, password};
                $.ajax({
                    url: "/file",
                    method: 'delete',
                    data: delVo,
                    success: function (res) {
                        if (res.code === 200) {
                            tableReload();
                            layer.closeAll();
                            layer.msg("删除成功", {icon: 1});
                        } else {
                            if (res.code === 5001) {
                                layer.msg(res.msg, {icon: 1});
                            } else {
                                layer.tips(res.msg, $("#password"));
                            }
                            return false;
                        }
                    }
                });
            });
            // 取消表单提交
            return false;
        });

        $("#qrCode").click(function () {
            layer.photos({
                photos: {
                    "title": "跳转",
                    "start": 0,
                    "data": [
                        {
                            "alt": "手机扫码",
                            "pid": 1,
                            "src": "/file/qrcode",
                        }
                    ]
                }
            });
            return false;
        });

        // 搜索提交
        form.on('submit(button-search)', function (data) {
            var field = data.field; // 获得表单字段
            // 执行搜索重载
            table.reload('table-file-list', {
                page: {
                    curr: 1 // 重新从第 1 页开始
                },
                where: field // 搜索的字段
            });
            return false; // 阻止默认 form 跳转
        });

        // 格式化字节
        function formatBytes(bytes) {
            if (bytes === 0) return '0 B';

            const k = 1024;
            const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));

            const formatted = (bytes / Math.pow(k, i)).toFixed(2);

            return `${formatted} ${sizes[i]}`;
        }

        // 重载表格
        function tableReload() {
            table.reload('table-file-list', {
                page: {
                    curr: 1 // 重新从第 1 页开始
                },
                where: {
                    originName: ''
                }
            });
        }

    });
</script>

</body>
</html>
